﻿using Share;
using System;
using UnityEngine;

// 通用工具类，提供各种静态方法用于数学计算、时间获取、列表处理等
public static class VectorTools
{
    // 定义静态常量以提高性能和可读性
    private const double RadiansToDegrees = 180 / Math.PI;
    /// <summary>
    /// 计算两个点在平面上的夹角
    /// </summary>
    /// <param name="start">起点，不能为零向量</param>
    /// <param name="end">终点，不能为零向量</param>
    /// <returns>两个点在平面上的夹角（单位：度）</returns>
    /// <exception cref="ArgumentException">当 start 或 end 为零向量时抛出异常</exception>
    public static float GetAnglePlane(Vector3 start, Vector3 end)
    {
        // 校验输入参数是否为零向量
        if (start == Vector3.zero || end == Vector3.zero)
        {
            throw new ArgumentException("输入参数 start 和 end 不能为零向量");
        }

        // 计算投影后的向量
        Vector3 projectedStart = start - Vector3.Project(start, Vector3.up);
        Vector3 projectedEnd = end - Vector3.Project(end, Vector3.up);

        // 再次校验投影后的向量是否为零向量
        if (projectedStart == Vector3.zero || projectedEnd == Vector3.zero)
        {
            throw new ArgumentException("投影后的向量不能为零向量");
        }

        // 计算夹角并返回
        return Vector3.Angle(projectedStart, projectedEnd);
    }

    /// <summary>
    /// 获取两个点之间的方向向量
    /// </summary>
    /// <param name="start">起点</param>
    /// <param name="end">终点</param>
    /// <returns>从起点指向终点的方向向量；如果起点和终点相同，则返回零向量</returns>
    public static Vector3 GetDirection(Vector3 start, Vector3 end)
    {
        // 计算从起点到终点的向量
        Vector3 direction = end - start;

        // 检查是否为零向量，避免 normalized 方法抛出异常
        if (direction.sqrMagnitude <= float.Epsilon)
        {
            // 如果是零向量，直接返回零向量
            return Vector3.zero;
        }

        // 返回归一化后的方向向量
        return direction.normalized;
    }

    /// <summary>
    /// 获取两个点之间的水平距离
    /// </summary>
    /// <param name="start">起点</param>
    /// <param name="end">终点</param>
    /// <returns>两个点之间的水平距离</returns>
    public static float GetDistance(Vector3 start, Vector3 end)
    {
        // 输入校验
        if (start == null || end == null)
        {
            throw new ArgumentNullException("输入参数不能为 null");
        }

        // 避免直接修改原始对象
        var startPoint = new Vector3(start.x, 0, start.z);
        var endPoint = new Vector3(end.x, 0, end.z);

        // 计算水平距离
        return Vector3.Distance(startPoint, endPoint);
    }

    /// <summary>
    /// 向量旋转
    /// </summary>
    /// <param name="from">原始向量（建议为单位向量）</param>
    /// <param name="to">目标向量（仅用于参考，不影响旋转结果）</param>
    /// <param name="degrees">旋转角度（单位：度）</param>
    /// <returns>旋转后的向量</returns>
    /// <exception cref="ArgumentException">当输入向量为零向量时抛出异常</exception>
    public static Vector3 RotateTowards(Vector3 from, Vector3 to, float degrees)
    {
        // 检查输入向量是否为零向量
        if (from == Vector3.zero || to == Vector3.zero)
        {
            throw new ArgumentException("输入向量不能为零向量");
        }

        // 规范化输入向量
        from = from.normalized;
        to = to.normalized;

        // 将角度归一化到 [-180, 180] 范围内
        degrees = NormalizeAngle(degrees);

        // 使用 Quaternion.AngleAxis 实现旋转
        return Quaternion.AngleAxis(degrees, Vector3.forward) * from;
    }

    /// <summary>
    /// 将角度归一化到 [-180, 180] 范围内
    /// </summary>
    /// <param name="angle">输入角度（单位：度）</param>
    /// <returns>归一化后的角度</returns>
    private static float NormalizeAngle(float angle)
    {
        angle = angle % 360; // 归一化到 [0, 360) 范围
        if (angle > 180)
        {
            angle -= 360; // 调整到 [-180, 180] 范围
        }
        return angle;
    }

    /// <summary>
    /// 计算两个向量的夹角
    /// </summary>
    /// <param name="vector1">第一个向量</param>
    /// <param name="vector2">第二个向量</param>
    /// <returns>两个向量的夹角（单位：度）</returns>
    /// <exception cref="ArgumentException">如果任意一个向量是零向量，则抛出异常</exception>
    public static float GetAngle(Vector3 vector1, Vector3 vector2)
    {
        // 检查零向量
        if (IsZeroVector(vector1) || IsZeroVector(vector2))
        {
            throw new ArgumentException("输入向量不能为零向量");
        }

        // 计算向量的叉积（用于计算正弦值）
        double crossProduct = vector1.x * vector2.z - vector2.x * vector1.z;

        // 计算向量的点积（用于计算余弦值）
        double dotProduct = vector1.x * vector2.x + vector1.z * vector2.z;


        // 计算夹角并返回
        return (float)(Math.Atan2(crossProduct, dotProduct) * RadiansToDegrees);
    }

    /// <summary>
    /// 判断一个向量是否为零向量
    /// </summary>
    /// <param name="vector">待判断的向量</param>
    /// <returns>是否为零向量</returns>
    private static bool IsZeroVector(Vector3 vector)
    {
        return vector.x == 0 && vector.z == 0;
    }

    /// <summary>
    /// 计算两个向量的夹角
    /// </summary>
    /// <param name="vector1">第一个向量</param>
    /// <param name="vector2">第二个向量</param>
    /// <returns>两个向量的夹角（单位：度）</returns>
    /// <exception cref="ArgumentException">当任意向量为零向量时抛出异常</exception>
    public static float GetAngle(Vector2 vector1, Vector2 vector2)
    {
        // 检查零向量
        if (vector1 == Vector2.zero || vector2 == Vector2.zero)
        {
            throw new ArgumentException("输入向量不能为零向量");
        }

        // 计算 sin 和 cos
        double sin = vector1.x * vector2.y - vector2.x * vector1.y;
        double cos = vector1.x * vector2.x + vector1.y * vector2.y;

        // 使用 Math.Atan2 计算弧度并转换为角度
        // Math.Atan2(sin, cos) 返回 [-π, π] 范围内的弧度值
        // 将弧度转换为角度，使用预定义的常量 RadiansToDegrees
        return (float)(Math.Atan2(sin, cos) * RadiansToDegrees);
    }

    /// <summary>
    /// 计算向量与正前方的夹角
    /// </summary>
    /// <param name="dir">向量</param>
    /// <returns>向量与正前方的夹角</returns>
    public static float GetAngle(Vector3 dir)
    {
        // 检查输入是否为零向量
        if (dir == Vector3.zero)
        {
            return 0; // 返回默认值 0，表示无方向
        }

        // 忽略 y 分量，仅保留 x 和 z 分量
        dir.y = 0;

        // 计算向量与正前方的叉积和点积
        Vector3 crossProduct = Vector3.Cross(dir, Vector3.forward);
        float dotProduct = Vector3.Dot(dir, Vector3.forward);

        // 使用 Atan2 计算角度
        float angle = Mathf.Atan2(crossProduct.magnitude, dotProduct) * Mathf.Rad2Deg;

        return angle;
    }


    /// <summary>
    /// 计算从一个向量旋转到另一个向量的有符号夹角
    /// </summary>
    /// <param name="from">原始向量</param>
    /// <param name="to">目标向量</param>
    /// <param name="dir">旋转轴方向</param>
    /// <returns>有符号夹角</returns>
    public static float SignedAngleBetween(Vector3 from, Vector3 to, Vector3 dir)
    {
        // 输入验证：确保 from、to 和 dir 不是零向量
        if (from == Vector3.zero || to == Vector3.zero || dir == Vector3.zero)
        {
            throw new ArgumentException("输入向量不能为零向量");
        }

        // 计算无符号夹角
        float angle = Vector3.Angle(from, to);

        // 边界条件：如果角度为0，直接返回0
        if (Mathf.Approximately(angle, 0f))
        {
            return 0f;
        }

        // 计算叉积和点积
        Vector3 crossProduct = Vector3.Cross(from, to);
        float sign = Mathf.Sign(Vector3.Dot(dir, crossProduct));

        // 计算有符号夹角
        float signed_angle = angle * sign;

        // 调整角度范围：确保结果在 [0, 360) 内
        if (signed_angle < 0)
        {
            signed_angle += 360f;
        }

        return signed_angle;
    }


    /// <summary>
    /// 旋转一个矢量
    /// </summary>
    /// <param name="dir">原始方向</param>
    /// <param name="axis">旋转轴（必须是非零向量）</param>
    /// <param name="angle">旋转角度（以度为单位）</param>
    /// <returns>旋转后的矢量</returns>
    /// <exception cref="ArgumentException">当旋转轴为零向量时抛出</exception>
    public static Vector3 RotateVector(Vector3 dir, Vector3 axis, float angle)
    {
        // 校验旋转轴是否为零向量
        if (axis == Vector3.zero)
        {
            throw new ArgumentException("旋转轴不能为零向量", nameof(axis));
        }

        // 使用 Quaternion.AngleAxis 进行旋转
        return Quaternion.AngleAxis(angle, axis) * dir;
    }
    /// <summary>
    /// 旋转一个点围绕指定中心点和旋转轴。
    /// </summary>
    /// <param name="position">点的位置</param>
    /// <param name="center">中心点的位置</param>
    /// <param name="axis">旋转轴（需为单位向量）</param>
    /// <param name="angle">旋转角度（以弧度为单位）</param>
    /// <returns>旋转后的点的位置</returns>
    public static Vector3 RotateRound(Vector3 position, Vector3 center, Vector3 axis, float angle)
    {
        // 校验输入参数的有效性
        if (float.IsNaN(angle) || float.IsInfinity(angle))
        {
            throw new ArgumentException("旋转角度必须是有限的数值", nameof(angle));
        }

        if (axis.sqrMagnitude < Mathf.Epsilon)
        {
            throw new ArgumentException("旋转轴不能为零向量", nameof(axis));
        }

        // 计算从中心点到目标点的方向向量
        var dir = position - center;

        // 如果方向向量为零，直接返回中心点位置
        if (dir.sqrMagnitude < Mathf.Epsilon)
        {
            return center;
        }

        // 确保旋转轴为单位向量
        axis = axis.normalized;

        // 使用 Rodrigues' rotation formula 进行旋转
        var cosTheta = Mathf.Cos(angle);
        var sinTheta = Mathf.Sin(angle);
        var rotatedDir = dir * cosTheta +
                        Vector3.Cross(axis, dir) * sinTheta +
                        axis * Vector3.Dot(axis, dir) * (1 - cosTheta);

        // 返回旋转后的新位置
        return center + rotatedDir;
    }

    /// <summary>
    /// 得到一个向量的法线，相对于up或者forward的法线
    /// </summary>
    /// <param name="dir">原始向量</param>
    /// <param name="dir2">参考向量</param>
    /// <returns>法线向量</returns>
    public static Vector3 GetNormalLine(Vector3 dir, Vector3 dir2)
    {
        // 如果和正上方重合了，
        if (dir.Equals(Vector3.up))
        {
            return Vector3.Cross(dir, dir2);
        }
        return -Vector3.Cross(dir, Vector3.up);
    }


    /// <summary>
    /// 检查一个点是否在指定的矩形区域内
    /// </summary>
    /// <param name="center">矩形区域的中心点</param>
    /// <param name="dirIn">矩形区域的方向</param>
    /// <param name="fWidth">矩形区域的宽度</param>
    /// <param name="fHeight">矩形区域的高度</param>
    /// <param name="targetPos">目标点的位置</param>
    /// <param name="targetRadius">目标点的半径</param>
    /// <returns>如果点在矩形区域内返回true，否则返回false</returns>
    public static bool IsPointInBox(Vector3 center, Vector3 dirIn, float fWidth, float fHeight, Vector3 targetPos, float targetRadius)
    {
        float fDir = GetAngle(dirIn);
        return IsPointInBox(center, fDir, fWidth, fHeight, targetPos, targetRadius);
    }

    /// <summary>
    /// 检查一个点是否在指定的矩形区域内
    /// </summary>
    /// <param name="center">矩形区域的中心点</param>
    /// <param name="fDir">矩形区域的方向角度</param>
    /// <param name="fWidth">矩形区域的宽度</param>
    /// <param name="fHeight">矩形区域的高度</param>
    /// <param name="targetPos">目标点的位置</param>
    /// <param name="targetRadius">目标点的半径</param>
    /// <returns>如果点在矩形区域内返回true，否则返回false</returns>
    public static bool IsPointInBox(Vector3 center, float fDir, float fWidth, float fHeight, Vector3 targetPos, float targetRadius)
    {
        // 参数校验
        if (fWidth <= 0 || fHeight <= 0 || targetRadius < 0)
        {
            throw new ArgumentException("宽度、高度必须为正数，目标半径不能为负数");
        }

        // 容差值，用于处理浮点数精度问题
        const float epsilon = 1e-6f;

        // 将目标点旋转到矩形的局部坐标系
        var rotatedPos = RotateRound(targetPos, center, Vector3.up, fDir);

        // 计算矩形的边界范围
        float minX = center.x - fWidth / 2 - targetRadius - epsilon;
        float maxX = center.x + fWidth / 2 + targetRadius + epsilon;
        float minZ = center.z - fHeight / 2 - targetRadius - epsilon;
        float maxZ = center.z + fHeight / 2 + targetRadius + epsilon;

        // 判断目标点是否在矩形范围内
        return rotatedPos.x >= minX && rotatedPos.x <= maxX &&
               rotatedPos.z >= minZ && rotatedPos.z <= maxZ;
    }

    /// <summary>
    /// 检查一个点是否在指定的圆形区域内
    /// </summary>
    /// <param name="center">圆形区域的中心点</param>
    /// <param name="fRadius">圆形区域的半径</param>
    /// <param name="targetPos">目标点的位置</param>
    /// <param name="targetRadius">目标点的半径</param>
    /// <param name="fMin">最小距离</param>
    /// <returns>如果点在圆形区域内返回true，否则返回false</returns>
    public static bool IsPointInCircle(Vector3 center, float fRadius, Vector3 targetPos, float targetRadius, float fMin = 0)
    {
        center.y = 0;
        targetPos.y = 0;
        var dis = GetDistance(center, targetPos);
        if (dis > fRadius + targetRadius || dis < fMin)
            return false;
        return true;
    }
    /// <summary>
    /// 检查一个点是否在指定的椭圆区域内
    /// </summary>
    /// <param name="centerPos">椭圆区域的中心点</param>
    /// <param name="dirIn">椭圆区域的方向</param>
    /// <param name="fMinRadius">椭圆区域的最小半径</param>
    /// <param name="fMaxRadius">椭圆区域的最大半径</param>
    /// <param name="pos">目标点的位置</param>
    /// <param name="targetRadius">目标点的半径</param>
    /// <returns>如果点在椭圆区域内返回true，否则返回false</returns>
    public static bool IsPointInEllipse(Vector3 centerPos, Vector3 dirIn, float fMinRadius, float fMaxRadius, Vector3 pos, float targetRadius)
    {
        // 参数校验
        if (fMinRadius <= 0 || fMaxRadius <= 0 || fMinRadius > fMaxRadius)
        {
            throw new ArgumentException("Invalid parameters: fMinRadius must be less than fMaxRadius and both must be positive.");
        }
        if (dirIn == Vector3.zero)
        {
            throw new ArgumentException("Invalid parameter: dirIn cannot be a zero vector.");
        }

        // 计算椭圆的两个焦点
        var focus1 = centerPos - dirIn.normalized * fMinRadius;
        var focus2 = centerPos + dirIn.normalized * fMinRadius;

        // 初步判断点是否在椭圆内
        var squaredDistance1 = GetSquaredDistance(pos, focus1);
        var squaredDistance2 = GetSquaredDistance(pos, focus2);

        var totalDistance = Mathf.Sqrt(squaredDistance1) + Mathf.Sqrt(squaredDistance2);
        if (totalDistance < fMaxRadius * 2)
        {
            return true;
        }

        // 处理目标点有额外半径的情况
        if (targetRadius > 0)
        {
            try
            {
                // 获取近的焦点方向
                var direction1 = focus1 - pos;
                var direction2 = focus2 - pos;

                if (direction1.sqrMagnitude == 0 || direction2.sqrMagnitude == 0)
                {
                    throw new InvalidOperationException("Zero vector encountered during normalization.");
                }

                direction1.Normalize();
                direction2.Normalize();

                // 计算旋转角度并调整目标点位置
                var angle = -GetAngle(direction1, direction2);
                var adjustedDirection = RotateVector(direction1, Vector3.up, angle / 2);
                adjustedDirection.Normalize();
                pos += adjustedDirection * targetRadius;

                // 重新计算距离
                squaredDistance1 = GetSquaredDistance(pos, focus1);
                squaredDistance2 = GetSquaredDistance(pos, focus2);

                totalDistance = Mathf.Sqrt(squaredDistance1) + Mathf.Sqrt(squaredDistance2);
                if (totalDistance < fMaxRadius * 2)
                {
                    return true;
                }
            }
            catch (InvalidOperationException ex)
            {
                XKLog.LogError($"Invalid operation encountered: {ex.Message}");
            }
            catch (Exception ex)
            {
                XKLog.LogError($"Unexpected error in adjusting target point: {ex.Message}");
            }
        }

        return false;
    }

    /// <summary>
    /// 计算两点之间的平方距离
    /// </summary>
    private static float GetSquaredDistance(Vector3 a, Vector3 b)
    {
        return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y) + (a.z - b.z) * (a.z - b.z);
    }



    /// <summary>
    /// 计算扇形和圆形是否相交
    /// </summary>
    /// <param name="circleCenter">圆形的中心点</param>
    /// <param name="circleRadius">圆形的半径</param>
    /// <param name="sectorCenter">扇形的中心点</param>
    /// <param name="sectorDirection">扇形的方向（向量）</param>
    /// <param name="sectorRadius">扇形的半径</param>
    /// <param name="sectorAngle">扇形的角度（以度为单位）</param>
    /// <returns>如果扇形和圆形相交返回true，否则返回false</returns>
    public static bool IsCircleIntersectSector(Vector3 circleCenter, float circleRadius, Vector3 sectorCenter, Vector3 sectorDirection, float sectorRadius, float sectorAngle)
    {
        // 参数校验
        if (circleRadius < 0 || sectorRadius < 0)
        {
            throw new ArgumentException("圆的半径和扇形的半径必须为非负数");
        }

        // 计算两圆心之间的距离
        float distance = GetDistance(circleCenter, sectorCenter);

        // 如果两圆心距离大于两半径之和，则不可能相交
        if (distance > circleRadius + sectorRadius)
        {
            return false;
        }

        // 特殊情况：两圆心重合
        if (distance == 0)
        {
            // 如果扇形角度为0，则扇形退化为一条线段，无法与圆形相交
            if (sectorAngle == 0)
            {
                return false;
            }
            // 否则，圆形完全位于扇形内或外
            return sectorRadius >= circleRadius;
        }

        // 计算圆心连线向量
        Vector3 line = circleCenter - sectorCenter;

        // 计算圆心连线与扇形方向向量之间的夹角
        float angleBetweenVectors = GetAngle(line, sectorDirection);

        // 计算圆形边缘点相对于扇形中心的最大偏移角度
        float maxOffsetAngle = Mathf.Rad2Deg * Mathf.Asin(circleRadius / distance);

        // 判断夹角是否在扇形角度范围内
        float halfSectorAngle = sectorAngle / 2;
        if (Mathf.Abs(angleBetweenVectors) <= halfSectorAngle + maxOffsetAngle)
        {
            return true;
        }

        return false;
    }

    /// <summary>
    /// 检查一个点是否在指定的扇形区域内
    /// </summary>
    /// <param name="center">扇形的中心点</param>
    /// <param name="dir">扇形的方向</param>
    /// <param name="radius">扇形的半径</param>
    /// <param name="angel">扇形的角度</param>
    /// <param name="pos">目标点的位置</param>
    /// <param name="targetRadius">目标点的半径</param>
    /// <returns>如果点在扇形区域内返回true，否则返回false</returns>
    public static bool IsPointInSector(Vector3 center, Vector3 dir, float radius, float angel, Vector3 pos, float targetRadius)
    {
        center.y = 0;
        pos.y = 0;
        var dir1 = pos - center;
        var dis = dir1.magnitude;
        var fCheckAngel = angel / 2;
        var fAngel = Vector3.Angle(dir, dir1);
        if (dis < targetRadius)
            return true;
        // 需要对判断半径做一次调整
        if (targetRadius > 0.1f && dis > 0.1f)
        {
            fCheckAngel += Mathf.Rad2Deg * Mathf.Atan(targetRadius / dis);
        }
        if (fAngel < fCheckAngel) // 判断角度
        {
            if (dis < radius + targetRadius)
            {
                return true;
            }
        }
        return false;
    }
    /// <summary>
    /// 指定点以 forward 方向偏移 posOffset 的大小。
    /// </summary>
    /// <param name="position">初始位置向量。</param>
    /// <param name="forward">前进方向向量，必须为非零向量。</param>
    /// <param name="posOffset">偏移量向量，表示在 forward 方向上移动的距离。</param>
    /// <returns>偏移后的位置向量。</returns>
    /// <exception cref="ArgumentException">当 forward 或 posOffset 为零向量时抛出。</exception>
    internal static Vector3 MoveVector(Vector3 position, Vector3 forward, Vector3 posOffset)
    {
        // 校验 forward 是否为零向量
        if (forward == Vector3.zero)
        {
            throw new ArgumentException("前进方向向量 forward 不能为零向量。", nameof(forward));
        }

        // 校验 posOffset 是否为零向量
        if (posOffset == Vector3.zero)
        {
            throw new ArgumentException("偏移量向量 posOffset 不能为零向量。", nameof(posOffset));
        }

        // 计算偏移后的向量
        // 将 forward 归一化，然后乘以 posOffset 的大小，得到最终偏移量
        Vector3 normalizedForward = forward.normalized;
        Vector3 offset = normalizedForward * posOffset.magnitude;

        return position + offset;
    }

    // 场景坐标转换为屏幕坐标
    /// <summary>
    /// 将3D场景坐标转换为屏幕像素坐标
    /// </summary>
    /// <param name="position">3D世界坐标</param>
    /// <returns>屏幕坐标(像素值，左下角为原点)，z<0时返回(-1,-1)</returns>
    internal static Vector2 ScenePosition2ScreenPosition(Vector3 position)
    {
        if (Camera.main == null)
        {
            Debug.LogError("Main camera not found!");
            return Vector2.zero;
        }

        Vector3 screenPos = Camera.main.WorldToScreenPoint(position);

        // 如果z<0表示物体在相机后方，返回无效坐标
        if (screenPos.z < 0)
        {
            return new Vector2(-1, -1);
        }

        return new Vector2(screenPos.x, screenPos.y);
    }

    /// <summary>
    /// 将屏幕坐标转换为UI本地坐标
    /// </summary>
    /// <param name="screenPos">屏幕坐标</param>
    /// <param name="rectTransform">目标UI的RectTransform</param>
    /// <param name="canvas">所属Canvas</param>
    /// <returns>UI本地坐标</returns>
    internal static Vector2 ScreenPositionToUILocalPosition(Vector2 screenPos, RectTransform rectTransform, Canvas canvas)
    {
        if (rectTransform == null || canvas == null)
        {
            Debug.LogError("RectTransform or Canvas is null!");
            return Vector2.zero;
        }

        Vector2 localPos;
        RectTransformUtility.ScreenPointToLocalPointInRectangle(
            rectTransform.parent.GetComponent<RectTransform>(),
            screenPos,
            CameraMgr.Instance.GetUICamera(),
            out localPos);

        return localPos;
    }

    /// <summary>
    /// 将3D场景坐标直接转换为UI本地坐标
    /// </summary>
    /// <param name="worldPos">3D世界坐标</param>
    /// <param name="rectTransform">目标UI的RectTransform</param>
    /// <param name="canvas">所属Canvas</param>
    /// <returns>UI本地坐标</returns>
    internal static Vector2 ScenePositionToUILocalPosition(Vector3 worldPos, RectTransform rectTransform, Canvas canvas)
    {
        Vector2 screenPos = ScenePosition2ScreenPosition(worldPos);
        if (screenPos.x < 0) return Vector2.zero; // 无效坐标

        return ScreenPositionToUILocalPosition(screenPos, rectTransform, canvas);
    }

    internal static Vector2 GetCenter(Vector3 pos, Vector3 pos2)
    {
        return (pos + pos2) / 2;
    }

    /// <summary>
    /// 判断一个值是否在指定的区间内
    /// </summary>
    /// <param name="value">要判断的值</param>
    /// <param name="start">区间起始值</param>
    /// <param name="end">区间结束值</param>
    /// <returns>如果值在区间内返回true，否则返回false</returns>
    internal static bool IsValueInSection(float value, float start, float end)
    {
        // 处理区间边界相等的情况
        if (Mathf.Approximately(start, end))
        {
            return Mathf.Approximately(value, start);
        }

        // 判断值是否在区间内（包含边界）
        if (start < end)
        {
            return value >= start && value <= end;
        }
        else
        {
            return value >= end && value <= start;
        }
    }
}
